<?php

class BaseForm extends sfFormSymfony
{
    const SQUARE_BRACKETS_GLUE  = '1';
    const UNDERSCORE_GLUE       = '2';

    protected $responseData = array();

    /**
     * Returneaza denumirea formularului
     * @return string
     */
    public function getFormName()
    {
        $formName = @constant(get_called_class().'::NAME');

        return $formName;
    }

    protected $_wrappers = array('%s'); // the first wrapper is the name of the field

    /**
     * Adauga la denumirea formularului un alt termen
     * @param string $name
     */
    public function setWrapperName($name)
    {
        $this->_wrappers[] = $name;
        $format = '';

        for ($i=0; $i < count($this->_wrappers) - 1; $i++)
        {
            $format = '[' . $this->_wrappers[$i] . ']' . $format;
        }
        $format = $this->_wrappers[$i] . $format;

        $this->getWidgetSchema()->setNameFormat($format);
    }

    // configurari generale
    protected function init()
    {
        // campurile formularului sunt precedate de un prefix (numele de baza al formularului)
        $formName = $this->getFormName();
        $this->setWrapperName($formName);

    }

    /**
     * --OVERRIDALBE--
     *
     * Based on $taintedValues the formSchema can be altered (add/remove fields or embedded forms)
     * This method will be defined by derived classes
     */
    protected function _prepareFormSchema(array &$taintedValues) {}

    /**
     * Alter the formSchema. Not overridable.
     */
    final protected function prepareFormSchema(array &$taintedValues)
    {
        $this->_prepareFormSchema($taintedValues);

        // also apply the method to embedded forms, if any
        foreach ($this->getEmbeddedForms() as $formName => $form)
        {
            if (!isset($taintedValues[$formName])) continue;

            $form->prepareFormSchema($taintedValues[$formName]);

            // re-embed forms
            $this->embedForm($formName, $form);
        }
    }

    public function bind(array $taintedValues = null, array $taintedFiles = null)
    {
        // reset response data
        $this->responseData = array();

        $this->prepareFormSchema($taintedValues);

        parent::bind($taintedValues, $taintedFiles);
    }

    /**
     * Sets the form widgets labels
     *
     * @param array $labels
     */
    public function setLabels(array $labels)
    {
        $this->getWidgetSchema()->setLabels($labels);

        return $this;
    }

    /**
     * Dupa procesarea formularului, se pot trimite anumite informatii
     * Metoda se va rescrie in clasele derivate
     *
     * @return array (!important)
     */
    public function getResponseData()
    {
        return $this->responseData;
    }

    /**
     * Returneaza erorile dintr-un formular
     *
     * @return array
     */
    public function getErrors()
    {
        /** erori globale */
        $globalErrors = array();
        foreach ($this->getGlobalErrors() as $error)
        {
            $globalErrors[] = $error->getMessage();
        }

        /** erorile pentru fiecare camp */
        $fieldErrors = self::getErrorsAsArray($this->getErrorSchema());
        $fieldErrors = self::plainArray($fieldErrors, self::SQUARE_BRACKETS_GLUE);

        foreach ($fieldErrors as $key => $value)
        {
            $name = $this->getWidgetSchema()->generateName($key);
            $id = $this->getWidgetSchema()->generateId($name);

            unset($fieldErrors[$key]);
            $fieldErrors[$name] = $value;
        }

        return array(
            'fields' => $fieldErrors,
            'global' => $globalErrors,
        );
    }

    static protected function getErrorsAsArray(sfValidatorErrorSchema $errorSchema)
    {
        $array = array();
        foreach ($errorSchema as $key => $error)
        {
            if ($error instanceof sfValidatorErrorSchema)
            {
                $errors = self::getErrorsAsArray($error);
                if (count($errors))
                {
                    $array[$key] = $errors;
                }
            }
            else
            {
                $array[$key] = $error->getMessage();
            }
        }

        return $array;
    }

    /**
     * Converts a multidimensional array into a plain array having the keys glued in some ways
     * @param array $array
     * @return array
     */
    protected static function plainArray(array $array, $glue)
    {
        $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
        $keys = array();
        foreach ($iterator as $key => $value)
        {
            // Build long key name based on parent keys
            $subKeys = array();
            for ($i = 0; $i < $iterator->getDepth(); $i++)
            {
                $subKeys[] = $iterator->getSubIterator($i)->key();
            }
            $subKeys[] = $key;

            switch ($glue)
            {
                case self::SQUARE_BRACKETS_GLUE:
                    $string = '';
                    foreach ($subKeys as $index => $subKey)
                    {
                        if ($index)
                        {
                            $string .= '[' . $subKey . ']';
                        }
                        else
                        {
                            $string = $subKey;
                        }

                    }
                    $subKeys = $string;

                    break;

                case self::UNDERSCORE_GLUE:
                    $subKeys = implode('_', $subKeys);

                    break;
            }

            $keys[$subKeys] = $value;
        }

        return $keys;
    }

    /**
     * Elimina dintr-un form anumite campuri
     * @param array $field_path
     */
    public function delete(array $field_path)
    {
        $widgetSchema = $this->getWidgetSchema();
        $validatorSchema = $this->getValidatorSchema();
        $embeddedForm = $this;

        $field = array_pop($field_path);
        foreach ($field_path as $path)
        {
            $widgetSchema = $widgetSchema[$path];
            $validatorSchema = $validatorSchema[$path];
            $embeddedForm = $embeddedForm->getEmbeddedForm($path);
        }

        unset($widgetSchema[$field], $validatorSchema[$field], $embeddedForm[$field]);

        return $this;
    }

}
